/*
 ============================================================================
 Name		: CDownloadEngine.cpp
 Author	  : William
 Version	 : 1.0
 Copyright   : Your copyright notice
 Description : CDownloadEngine implementation
 ============================================================================
 */
#include <avkon.hrh>
#include <aknnotewrappers.h>
#include <uri8.h>
#include <http.h>
#include <chttpformencoder.h>
#include <HttpStringConstants.h>
#include <http\RHTTPTransaction.h>
#include <http\RHTTPSession.h>
#include <http\RHTTPHeaders.h>

#include <COMMDB.H> 		//Communications database 
#include <CDBPREFTABLE.H>	//Connection Preferences table
#include <CommDbConnPref.h>

#include <EIKENV.H>
#include <BAUTILS.H>

#include "mydatacenter.h"
#include "MyUtils.h"

#include "DownloadEngine.h"
extern MyDataCenter* iDataCenter;	

// Used user agent for requests
_LIT8(KUserAgent, "SimpleClient 1.0");

// This client accepts all content types.
_LIT8(KAccept, "*/*");

_LIT8(KRange, "bytes=");
const TInt KInfotextBufferSize = 64;

CDownloadEngine::CDownloadEngine()
{
	iFs.Connect();
	// No implementation required
	iConnectionSetupDone = false;
	m_recv_bytes = 0;
}

CDownloadEngine::~CDownloadEngine()
{
	iFs.Close();
	iFile.Close();
}

CDownloadEngine* CDownloadEngine::NewLC()
{
	CDownloadEngine* self = new (ELeave) CDownloadEngine();
	CleanupStack::PushL(self);
	self->ConstructL();
	return self;
}

CDownloadEngine* CDownloadEngine::NewL()
{
	CDownloadEngine* self = CDownloadEngine::NewLC();
	CleanupStack::Pop(); // self;
	return self;
}

void CDownloadEngine::ConstructL()
{
	// Open RHTTPSession with default protocol ("HTTP/TCP")
	TRAPD(err, iSession.OpenL());
	if(err != KErrNone) 
		{
		// Most common error; no access point configured, and session creation
		// leaves with KErrNotFound.
		_LIT(KErrMsg,
			"Cannot create session. Is internet access point configured?");
		_LIT(KExitingApp, "Exiting app.");
		//CEikonEnv::Static()->InfoWinL(KErrMsg, KExitingApp);
		User::Leave(err);
		}

	// Install this class as the callback for authentication requests. When
	// page requires authentication the framework calls GetCredentialsL to get
	// user name and password.
	///InstallAuthenticationL(iSession);
}

void CDownloadEngine::AddHeaderL(RHTTPHeaders aHeaders,
							 TInt aHdrField,
							 const TDesC8& aHdrValue)
	{
	RStringF valStr = iSession.StringPool().OpenFStringL(aHdrValue);
	CleanupClosePushL(valStr);
	THTTPHdrVal val(valStr);
	aHeaders.SetFieldL(iSession.StringPool().StringF(aHdrField,
		RHTTPSession::GetTable()), val);
	CleanupStack::PopAndDestroy(); // valStr
	}

void CDownloadEngine::AddHeaderL(RHTTPHeaders aHeaders, const TDesC8& aHeaderField, const TDesC8& aHeaderValue)
{
	RStringPool stringPool = iSession.StringPool();
	RStringF valStr = stringPool.OpenFStringL(aHeaderValue);
	THTTPHdrVal headerVal(valStr);
	aHeaders.SetFieldL(stringPool.OpenFStringL(aHeaderField), headerVal);
	valStr.Close();
}

void CDownloadEngine::GetRequestL(const TDesC8& aUri)
{
	TBuf<100> folder;
	#ifdef _DEBUG		
		folder.Copy(_L("c:\\data\\iRead\\%S"));
	#else
		folder.Copy(_L("e:\\data\\iRead\\%S"));		
	#endif
	
	TBuf<256> uri;
	uri.Copy(aUri);
	TPtrC filename = DBUtil::Static()->GetUriFileName(uri);
	
	TBuf<256> filepath;
	filepath.Format(folder, &filename);//(filename, "c:\\itest\\down.txt");
	
	BaflUtils::EnsurePathExistsL(iFs, filepath);
	User::LeaveIfError(iFile.Replace(iFs, filepath, EFileWrite));
	
	m_total_bytes = 0;

	SetupConnectionL();
	
	 ///ParseUriL(aUri);//对URL地址进行分析 
	// Parse string to URI (as defined in RFC2396)
	iUriParser.Parse(aUri);

	 // Create the transaction
	 iTransaction = iSession.OpenTransactionL(iUriParser, *this,
			 iSession.StringPool().StringF(HTTP::EGET, RHTTPSession::GetTable()));

	 RHTTPHeaders headers = iTransaction.Request().GetHeaderCollection();

	 //添加HTTP请求消息头

	 AddHeaderL(headers, HTTP::EUserAgent, KUserAgent);
	 AddHeaderL(headers, HTTP::EAccept, KAccept);
	 // Set transaction headers
	 if (m_recv_bytes != 0)
	 {
//		 TBuf8 <20> aBufLength;
//		 aBufLength.SetLength(0);
//		 aBufLength.Append(KRange);
//		 aBufLength.AppendNum(m_recv_bytes);
//		 aBufLength.Append(_L("-"));//这里一定要注意了。如果是断点下载一定要加上这个，我可被这个害死了
//		 AddHeaderL(headers, HTTP::ERange,aBufLength);
	 }

	 // Submit the request
	 iTransaction.SubmitL();
}

void CDownloadEngine::GetHeaderL(RHTTPHeaders aHeaders, const TDesC8 &aHeaderField, THTTPHdrVal &aHeaderValue ) const
{
	RStringPool stringPool = iSession.StringPool();
	aHeaders.GetField(stringPool.OpenFStringL(aHeaderField), 0, aHeaderValue);	
}
/*
void CHTTPEngine::SetHeaderL(RHTTPHeaders aHeaders, const TDesC8& aHeaderField, const TDesC8& aHeaderValue)
	{
	RStringPool stringPool = iSession.StringPool();
	RStringF valStr = stringPool.OpenFStringL(aHeaderValue);
	THTTPHdrVal headerVal(valStr);
	aHeaders.SetFieldL(stringPool.OpenFStringL(aHeaderField), headerVal);
	valStr.Close();
	}*/
// ----------------------------------------------------------------------------
// CClientEngine::MHFRunL()
//
// Inherited from MHTTPTransactionCallback
// Called by framework to pass transaction events.
// ----------------------------------------------------------------------------
void CDownloadEngine::MHFRunL(RHTTPTransaction aTransaction,
						  const THTTPEvent& aEvent)
{
	switch (aEvent.iStatus)
		{
		case THTTPEvent::EGotResponseHeaders:
			{
				THTTPHdrVal aHeaderValue;
			    RHTTPResponse resp = aTransaction.Response();
			    RHTTPHeaders aHeaders = resp.GetHeaderCollection();
			    TRAPD(error,GetHeaderL (aHeaders, _L8("Content-Length"), aHeaderValue ));
			    //m_total_bytes = aHeaderValue.Int();
			    //m_total_bytes += m_recv_bytes;
			    TBuf<10> tttt;
			    tttt.Num(aHeaderValue.Int());
			    //CEikonEnv::Static()->InfoWinL(_L("test"), tttt);
			    iDataCenter->iWaitDlg.Note(tttt);
			}
			break;

		case THTTPEvent::EGotResponseBodyData:
			{
			//CEikonEnv::Static()->InfoWinL(_L("test"), _L("dsfs"));
			// Get the body data supplier
			MHTTPDataSupplier* body = aTransaction.Response().Body();
			
			TPtrC8 dataChunk;

			// GetNextDataPart() returns ETrue, if the received part is the last
			// one.
			TBool isLast = body->GetNextDataPart(dataChunk);
			
			//append to file
			//iObserverPtr->ClientReceived(iClientID, dataChunk);

			TBuf<KInfotextBufferSize> text;
			_LIT(KBodyPartReceived, "%d bytes received... ");
			m_total_bytes += dataChunk.Length();
			text.Format(KBodyPartReceived, m_total_bytes);//dataChunk.Length());
			iDataCenter->iWaitDlg.Note(text);
			int pos = 0;
			iFile.Write(dataChunk);
			//CEikonEnv::Static()->InfoWinL(_L("test"), text);
			//iObserverPtr->ClientEvent(iClientID, text);
			//display process
			
			
			// Always remember to release the body data.
			body->ReleaseData();
			}
			break;

		case THTTPEvent::EResponseComplete:
			{
			//CEikonEnv::Static()->InfoWinL(_L("test"), _L("tttt"));
				//iDataCenter->iWaitDlg.EndWait();
			iDataCenter->iWaitDlg.Note(_L("downloaded"), 3);
			TBuf<200> fullname;
			iFile.FullName(fullname);
			TBuf<50> filename;
			iFile.Name(filename);
			iFile.Close();
			//CEikonEnv::Static()->InfoWinL(_L("test"), filename);
			iDataCenter->AddBookToList(fullname, filename);
			}
			break;

		case THTTPEvent::ESucceeded:
			{

			}
			break;

		case THTTPEvent::EFailed:
			{

			}
			break;

		default:
			// There are more events in THTTPEvent, but they are not usually
			// needed. However, event status smaller than zero should be handled
			// correctly since it's error.
			{

			}
			break;
		}
}

TInt CDownloadEngine::MHFRunError(TInt aError, RHTTPTransaction aTransaction, const THTTPEvent& aEvent)
{
	return KErrNone;
}

// ----------------------------------------------------------------------------
// CClientEngine::SetupConnectionL()
//
// The method set the internet access point and connection setups.
// ----------------------------------------------------------------------------	
void CDownloadEngine::SetupConnectionL()
{
    if( iConnectionSetupDone )
        return;
    
    iConnectionSetupDone = ETrue;
  
    //open socket server and start the connection
    User::LeaveIfError(iSocketServ.Connect());
    User::LeaveIfError(iConnection.Open(iSocketServ));

//  just for the time being 
////#ifndef _DEBUG
////{
////	TCommDbConnPref connectPref;	
////    User::LeaveIfError(iConnection.Start(connectPref));	
////    //set the sessions connection info
////    RStringPool strPool = iSession.StringPool();
////    RHTTPConnectionInfo connInfo = iSession.ConnectionInfo();
////    
////    //to use our socket server and connection
////    connInfo.SetPropertyL ( strPool.StringF(HTTP::EHttpSocketServ,
////        RHTTPSession::GetTable() ), THTTPHdrVal (iSocketServ.Handle()) );
////
////    connInfo.SetPropertyL ( strPool.StringF(HTTP::EHttpSocketConnection,
////        RHTTPSession::GetTable() ), 
////        THTTPHdrVal (REINTERPRET_CAST(TInt, &(iConnection))) );
//////
////	return;    
////}
////#endif    
    // open the IAP communications database 
	CCommsDatabase* commDB = CCommsDatabase::NewL(EDatabaseTypeIAP);
	CleanupStack::PushL(commDB);

	// initialize a view 
	CCommsDbConnectionPrefTableView* commDBView = 
	commDB->OpenConnectionPrefTableInRankOrderLC(ECommDbConnectionDirectionUnknown);

	// go to the first record 
	User::LeaveIfError(commDBView->GotoFirstRecord());

	// Declare a prefTableView Object.
	CCommsDbConnectionPrefTableView::TCommDbIapConnectionPref pref;

	// read the connection preferences 
	commDBView->ReadConnectionPreferenceL(pref);
	TUint32 iapID = pref.iBearer.iIapId; 

	// pop and destroy the IAP View 
	CleanupStack::PopAndDestroy(commDBView);

	// pop and destroy the database object
	CleanupStack::PopAndDestroy(commDB);

	// Now we have the iap Id. Use it to connect for the connection.
	// Create a connection preference variable.
	TCommDbConnPref connectPref;

	// setup preferences 
	connectPref.SetDialogPreference(ECommDbDialogPrefDoNotPrompt);
	connectPref.SetDirection(ECommDbConnectionDirectionUnknown);
	connectPref.SetBearerSet(ECommDbBearerGPRS);
	//Sets the CommDb ID of the IAP to use for this connection
	connectPref.SetIapId(iapID);
    
    User::LeaveIfError(iConnection.Start(connectPref));
	
    //set the sessions connection info
    RStringPool strPool = iSession.StringPool();
    RHTTPConnectionInfo connInfo = iSession.ConnectionInfo();
    
    //to use our socket server and connection
    connInfo.SetPropertyL ( strPool.StringF(HTTP::EHttpSocketServ,
        RHTTPSession::GetTable() ), THTTPHdrVal (iSocketServ.Handle()) );

    connInfo.SetPropertyL ( strPool.StringF(HTTP::EHttpSocketConnection,
        RHTTPSession::GetTable() ), 
        THTTPHdrVal (REINTERPRET_CAST(TInt, &(iConnection))) );
        
 
}
